//接下来，我们来看看如何用js实现一个简单的异步并发任务控制器。首先，我们需要定义一个类来表示控制器对象，并在构造函数中初始化以下三个属性：
//`maxConcurrent`：最大并发数，也就是同时进行的异步任务数量。
//`currentConcurrent`：当前并发数，也就是正在进行中或者已经完成但还未从队列中移除的异步任务数量。
//`taskQueue`：任务队列，用一个数组来存储待执行或者正在执行中的返回promise对象函数。

// 定义一个异步任务控制器类
class AsyncTaskController {
    // 构造函数，接受最大并发数作为参数
    constructor() {
        // 初始化最大并发数
        this.maxConcurrent = 1;
        // 初始化当前并发数
        this.currentConcurrent = 0;
        // 初始化任务队列
        this.taskQueue = [];
    }

    setConcurrency(concurrency) {
        this.maxConcurrent = concurrency;
    }

    // 添加一个异步任务到队列中，接受一个返回promise的函数作为参数
    addTask(task) {
        // 将任务函数加入队列
        this.taskQueue.push(task);
    }

    // 执行下一个任务，如果当前并发数小于最大并发数，并且队列不为空，则从队列中取出一个任务并执行，否则什么都不做
    next() {
        if (this.currentConcurrent < this.maxConcurrent && this.taskQueue.length > 0) {
            // 取出队列中的第一个任务函数，并从队列中移除它
            const task = this.taskQueue.shift();
            // 增加当前并发数
            this.currentConcurrent++;

            // 执行任务函数，并处理其返回的promise对象
            task()
                .then((result) => {
                    // 如果成功，打印结果（或者做其他操作）
                    console.log(result);
                })
                .catch((error) => {
                    // 如果失败，打印错误（或者做其他操作）
                    console.error(`error: ${error}`);
                })
                .finally(() => {
                    // 不管成功还是失败，都要减少当前并发数，并执行下一个任务（递归调用）
                    this.currentConcurrent--;

                    setTimeout(() => {
                        this.next();
                    }, 0); // 使用 setTimeout 来避免立即递归调用
                });

            // 只要未达到并发数量的限制，就继续启动执行任务
            this.next();
        }
    }

    run() {
        this.next();
        return new Promise((resolve) => {
            // 当队列为空且当前并发数为0时，所有任务都已完成
            const checkCompletion = () => {
                if (this.taskQueue.length === 0 && this.currentConcurrent === 0) {
                    resolve(ticket);
                }
            };
            const ticket = setInterval(checkCompletion, 100); // 定期检查任务是否完成
        });
    }
}

// 测试代码

// 定义一些返回promise的函数作为模拟的异步任务

// 模拟成功的异步任务，接受一个id作为参数，返回一个延迟1秒后resolve的promise对象，值为id * 2
// const successTask = (id) => () =>
//     new Promise((resolve) => {
//         setTimeout(() => resolve(id), 1000);
//     });
function mockSuccessTask(id, timeout) {
    return () =>
        new Promise((resolve) => {
            setTimeout(() => resolve(id), timeout);
        });
}

// 模拟失败的异步任务，接受一个id作为参数，返回一个延迟1秒后reject的promise对象，值为id * -1
// const failTask = (id) => () =>
//     new Promise((_, reject) => {
//         setTimeout(() => reject(id * -1), 1000);
//     });
function mockFailTask(id, timeout) {
    return () =>
        new Promise((_, reject) => {
            setTimeout(() => reject(id * -1), timeout);
        });
}

// 创建一个异步任务控制器实例，最大并发数为2
const controller = new AsyncTaskController();
controller.setConcurrency(2);

// 添加一些异步任务到控制器中
// controller.addTask(successTask(1));
// controller.addTask(failTask(2));
// controller.addTask(successTask(3));
// controller.addTask(failTask(4));
// controller.addTask(successTask(5));
controller.addTask(mockSuccessTask(1, 500));
controller.addTask(mockFailTask(2, 100));
controller.addTask(mockSuccessTask(3, 100));
controller.addTask(mockFailTask(4, 300));
controller.addTask(mockSuccessTask(5, 500));
controller.addTask(mockFailTask(6, 200));

controller.run().then((ticket) => {
    console.log("All tasks completed.");
    clearInterval(ticket);
});
